package uy.edu.fing.pgsegesb.authentication;
import java.security.Principal;
import java.security.acl.Group;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.FailedLoginException;
import javax.security.auth.login.LoginException;

import java.security.Principal;
import org.jboss.security.SimpleGroup;

import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;

import  org.jboss.security.auth.spi.AbstractServerLoginModule;

import uy.edu.fing.pgsegesb.utils.RespuestaHttp;

public class SAMLLoginModule extends TokenLoginModule {
	
	 /** The login identity */
   private Principal identity;
   /** The proof of login identity */
   private char[] credential;
   
   private boolean ignorePasswordCase;
   
   private String idpURL = "http://localhost:8280/idp/j_security_check";
 
	public void initialize(Subject subject, CallbackHandler callbackHandler,
		      Map sharedState, Map options)
   {
	  ignorePasswordCase = false;
      super.initialize(subject, callbackHandler, sharedState, options);
      
   }

   /** Perform the authentication of the username and password.
    */
   public boolean login() throws LoginException
   {
	   System.out.println("Autenticando con SAMLLoginModule");
	   
	   	super.loginOk = false;
		String[] info = getUsernameAndPasswordFromMessage();
		String username = info[0];
		  String password = info[1];
		  String name = username.toString();
		  try
		  {
			 RespuestaHttp response = SAMLHelper.loginSAML("", idpURL, username, password);
			 if (response.code == 200)
			 {
			     identity = createIdentity(name);
			     String tmp = password.toString();
			     credential = tmp.toCharArray();
			     super.loginOk = true;
			     sharedState.put("javax.security.auth.login.name", username);
				 sharedState.put("javax.security.auth.login.password", credential);
			 }
			 else
			 {
				 log.debug("Failed to login: " + username);
			     throw new LoginException("Failed to login: "+ username);
			 }
		  }
		  catch(Exception e)
		  {
		     log.debug("Failed to create principal", e);
		     throw new LoginException("Failed to create principal: "+ e.getMessage());
		  }
		 
		 
	   return true;
   }


   protected Principal getUnauthenticatedIdentity()
   {
      return unauthenticatedIdentity;
   }

   protected Object getCredentials()
   {
      return credential;
   }
   protected String getUsername()
   {
      String username = null;
      if( getIdentity() != null )
         username = getIdentity().getName();
      return username;
   }
   
   protected boolean validatePassword(String inputPassword, String expectedPassword)
   {
      if( inputPassword == null || expectedPassword == null )
         return false;
      boolean valid = false;
      if( ignorePasswordCase == true )
         valid = inputPassword.equalsIgnoreCase(expectedPassword);
      else
         valid = inputPassword.equals(expectedPassword);
      return valid;
   }
   
   protected String getUsersPassword()
   {
	  System.out.println("Buscando entre los usuarios de SAMLLoginModule");
      String username = getUsername();
      String password = null;
      if (username != null)
      {
         if (username.compareTo("kermit")==0)
        	 password = "thefrog2";
         else
        	 System.out.println("No se pudo encontrar un usuario que matchee en WSTrustLoginModule para " + username);
      }
      return password;
   }
   

   /** Called by login() to acquire the username and password strings for
    authentication. This method does no validation of either.
    @return String[], [0] = username, [1] = password
    @exception LoginException thrown if CallbackHandler is not set or fails.
    */
   protected String[] getUsernameAndPasswordFromMessage() throws LoginException
   {
      String[] info = {null, null};
      // prompt for a username and password
      if( callbackHandler == null )
      {
         throw new LoginException("Error: no CallbackHandler available " +
         "to collect authentication information");
      }
      NameCallback nc = new NameCallback("User name: ", "guest");
      PasswordCallback pc = new PasswordCallback("Password: ", false);
      Callback[] callbacks = {nc, pc};
      String username = null;
      String password = null;
      try
      {
         callbackHandler.handle(callbacks);
         username = nc.getName();
         char[] tmpPassword = pc.getPassword();
         if( tmpPassword != null )
         {
            credential = new char[tmpPassword.length];
            System.arraycopy(tmpPassword, 0, credential, 0, tmpPassword.length);
            pc.clearPassword();
            password = new String(credential);
         }
      }
      catch(java.io.IOException ioe)
      {
         throw new LoginException(ioe.toString());
      }
      catch(UnsupportedCallbackException uce)
      {
         throw new LoginException("CallbackHandler does not support: " + uce.getCallback());
      }
      info[0] = username;
      info[1] = password;
      return info;
   }
	
	
	@Override
	protected Principal getIdentity() {
		return identity;
	}



	/** Create the set of roles the user belongs to by parsing the roles.properties
	data for username=role1,role2,... and username.XXX=role1,role2,...
	patterns.
	@return Group[] containing the sets of roles 
	*/
	@Override
	protected Group[] getRoleSets() throws LoginException
	{
		String targetUser = getUsername();
		Group[] roleSets = getRoleSetsHelper(targetUser, "");
		return roleSets;
	}
	
		
	private Group[] getRoleSetsHelper(String targetUser, String tokenSAMLconInfoDeAutorizacionDelUsr)
	   {
	      SimpleGroup rolesGroup = new SimpleGroup("AuthenticatedRol");
	      ArrayList groups = new ArrayList();
	      groups.add(rolesGroup);
	      // Aca hacemos algo para agregar algo asi como roles que vengan del STS?
	      Group[] roleSets = new Group[groups.size()];
	      groups.toArray(roleSets);
	      return roleSets;
	   }
}
